/*
 * Copyright (c) 2015-2020, www.dibo.ltd (service@dibo.ltd).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * https://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.icesoft.framework.core.handler;

import com.icesoft.framework.core.exception.BusinessException;
import com.icesoft.framework.core.exception.InvalidUsageException;
import com.icesoft.framework.core.util.V;
import com.icesoft.framework.core.vo.Status;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 全局异常统一处理的默认实现
 * （继承自该类并添加@ControllerAdvice注解即可自动支持兼容页面和JSON的异常处理）
 *
 * @author mazc@dibo.ltd
 * @version v2.0
 * @date 2019/07/19
 */
@Slf4j
@SuppressWarnings("JavaDoc")
public  class DefaultExceptionHandler {



	@ExceptionHandler({BindException.class, MethodArgumentNotValidException.class})
	public Object validExceptionHandler(Exception ex) {
		BindingResult br = null;
		if (ex instanceof BindException) {
			br = ((BindException) ex).getBindingResult();
		}
		Map<String, Object> map = new HashMap<>(8);
		if (br != null && br.hasErrors()) {
			map.put("code", Status.FAIL_VALIDATION.code());
			String validateErrorMsg = V.getBindingError(br);
			map.put("msg", validateErrorMsg);
			map.put("ok", false);
			log.warn("数据校验失败, {}: {}", br.getObjectName(), validateErrorMsg);
		}
		return new ResponseEntity<>(map, HttpStatus.OK);
	}

	@ExceptionHandler(BusinessException.class)
	public ResponseEntity<?> BusinessException(HttpServletRequest request, HttpServletResponse response, BusinessException exception) {
		log.error(exception.getMessage(), exception);
		Map<String, Object> map = new LinkedHashMap<>();
		map.put("code", exception.getStatus().code());
		map.put("msg", exception.getMessage());
		map.put("ok", false);
		return new ResponseEntity<>(map, HttpStatus.OK);
	}

	@ExceptionHandler({Exception.class})
	public Object handleException(HttpServletRequest request, Exception e) {
		log.error(e.getMessage(), e);
		HttpStatus status = this.getStatus(request);
		Object map;
		if (e instanceof BusinessException) {
			map = ((BusinessException)e).toMap();
		} else if (e.getCause() instanceof BusinessException) {
			map = ((BusinessException)e.getCause()).toMap();
		} else if (e instanceof InvalidUsageException) {
			map = ((InvalidUsageException)e).toMap();
		} else if (e.getCause() instanceof InvalidUsageException) {
			map = ((InvalidUsageException)e.getCause()).toMap();
		} else {
			map = new HashMap(8);
			((Map)map).put("code", status.value());
			String msg = this.buildMsg(status, e);
			((Map)map).put("msg", msg);
			((Map)map).put("ok", false);
		}

		log.warn("请求处理异常", e);
		return new ResponseEntity(map, HttpStatus.OK);
	}

	protected String buildMsg(HttpStatus status, Exception e) {
		return e == null ? status.getReasonPhrase() : getRootCauseMessage(e);
	}

	protected HttpStatus getStatus(HttpServletRequest request) {
		Integer statusCode = (Integer)request.getAttribute("javax.servlet.error.status_code");
		if (statusCode == null) {
			return HttpStatus.INTERNAL_SERVER_ERROR;
		} else {
			try {
				return HttpStatus.valueOf(statusCode);
			} catch (Exception var4) {
				return HttpStatus.INTERNAL_SERVER_ERROR;
			}
		}
	}
	public static String getRootCauseMessage(Throwable t) {
		List<Throwable> list = ExceptionUtils.getThrowableList(t);
		Assert.notEmpty(list, () -> "没有异常信息");
		return list.get(list.size() - 1).getMessage();
	}
}
